#include "clist.h"

typedef struct CListElmt_tag{
	void*		data;

	CListElmt*	next;
}CListELmt;

typedef struct CList_tag{
	int size;

	int (*match)(const void* key1, const void* key2);
	void (*destroy)(void* data);

	CListElmt* head;
}CList;

CList* clist_create(void (*destroy)(void* data))
{
	CList* list;
	assert(NULL != (list=(CList* )malloc(sizeof(CList))));
	assert(NULL != destroy);

	list->size = 0;
	list->destroy = destroy;

	list->head = NULL;

	return list;
}
void clist_destroy(CList* list)
{
	void* data;
	assert(NULL != list);
	assert(NULL != list->destroy);

	while(list->size > 0)
	{
		if (clist_rmv_next(list, NULL, &data))
		{
			list->destroy(data);
		}
	}
	free(list);
	list = NULL;
}
int clist_ins_next(CList* list, \
				   CListElmt* element, const void* data)
{
	CListElmt* new_element;
	assert(NULL != list);
	assert(NULL != (new_element=(CListElmt* )malloc(sizeof(CListElmt))));
	new_element->data = (void* )data;
	
	if (list->size == 0)		//empty list
	{
		new_element->next = new_element;
		list->head = new_element;
	}
	else						//or
	{
		/* if the list has more than 1 elements, then 
		   we can't insert element as head. */
		assert(NULL != element); 
		new_element->next = element->next;
		element->next = new_element;
	}

	list->size++;
	return 0;
}
int clist_rmv_next(CList* list, \
				   CListElmt* element, void** data)
{
	CListElmt* old_element;
	assert(NULL != list && list->size > 0);
	assert(NULL != element);

	*data = element->next->data;
	if (element->next == element)		//the last one element
	{
		old_element = element->next;
		list->head = NULL;
	}
	else								//or 
	{
		old_element = element->next;
		element->next = old_element->next;
		if (clist_is_head(list,old_element)) //if head of list was changed
		{
			list->head = old_element->next;
		}
	}
	
	free(old_element);
	list->size--;
	return 0;
}

int clist_size(const CList* list)
{
	return list->size;
}
CListElmt* clist_head(const CList* list)
{
	return list->head;
}
int clist_is_head(const CList* list,\
				  const CListElmt* element)
{
	return (list->head == element ? 1 : 0);
}

void* clist_data(const CListElmt* element)
{
	return element->data;
}
CListElmt* clist_next(const CListElmt* element)
{
	return element->next;
}
